package com.asura.framework.rulemodel;

import java.util.Collections;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.util.Assert;

import com.asura.framework.rulemodel.engine.DefaultRuleTreeEngine;
import com.asura.framework.rulemodel.engine.RuleTreeEngine;
import com.asura.framework.rulemodel.engine.dao.entity.RuleModelEntity;
import com.asura.framework.rulemodel.engine.dao.read.RuleModelReadMapper;

/**
 * 规则模型监听器.
 * <p>
 * 监听系统规则模型, 从数据库中加载可用规则到内存中.
 * </p>
 * 
 * @author a123
 *
 */
public class RuleTreeListener implements ApplicationListener< ContextRefreshedEvent >, FactoryBean< RuleTreeEngine >,
InitializingBean{

	private final static Logger logger = LoggerFactory.getLogger( RuleTreeListener.class );

	private RuleTreeEngine ruleTreeEngine;

	public void setRuleTreeEngine( RuleTreeEngine ruleTreeEngine )
	{
		this.ruleTreeEngine = ruleTreeEngine;
	}

	private RuleModelReadMapper ruleModelReadMapper;

	public void setRuleModelReadMapper( RuleModelReadMapper ruleModelReadMapper )
	{
		this.ruleModelReadMapper = ruleModelReadMapper;
	}

	private boolean fastFail = true;

	/**
	 * 快速失败, 默认为: true.
	 * <p>
	 * 表示当容器初始化过程中, 未成功加载规则模型情况下是否销毁容器.
	 * </p>
	 */
	public void setFastFail( boolean fastFail )
	{
		this.fastFail = fastFail;
	}

	@Override
	public RuleTreeEngine getObject( ) throws Exception
	{
		return ruleTreeEngine;
	}

	@Override
	public Class< ? > getObjectType( )
	{
		return RuleTreeEngine.class;
	}

	@Override
	public boolean isSingleton( )
	{
		return true;
	}

	@Override
	public void onApplicationEvent( ContextRefreshedEvent event )
	{
		load( );
	}

	private void load( )
	{
		List< RuleModelEntity > rules = loadRuleModel( );
		if ( rules == null )
		{
			logger.warn( "规则模型 --> 无可用规则" );
			return;
		}

		assembly( rules );
	}

	protected List< RuleModelEntity > loadRuleModel( )
	{
		List< RuleModelEntity > rules = null;
		try
		{
			rules = ruleModelReadMapper.queryAllAvailableRuleModel( );
		} catch ( Throwable e )
		{
			if ( fastFail )
			{
				throw new ApplicationContextException( "规则模型加载失败", e );
			}
			logger.warn( "规则模型 --> 加载失败.", e );
			rules = Collections.emptyList( );
		}
		return rules;
	}

	private void assembly( List< RuleModelEntity > rules )
	{
		if ( logger.isInfoEnabled( ) )
		{
			logger.info( "==========> 规则模型树 - 构建中 <==========" );
		}
		for ( RuleModelEntity rule : rules )
		{
			TreeNode treeNode = convert( rule );
			ruleTreeEngine.addTreeNode( treeNode );
			if ( logger.isInfoEnabled( ) )
			{
				logger.info( "规则树 --> " + treeNode );
			}
		}

		if ( logger.isInfoEnabled( ) )
		{
			logger.info( "==========> 规则模型树 - 构建完毕 <==========" );
		}
	}

	/**
	 * 转换规则模型为树节点.
	 * 
	 * @param rule
	 * @return
	 */
	private TreeNode convert( RuleModelEntity rule )
	{
		TreeNode node = new TreeNode( rule.getName( ) );
		node.setType( rule.getType( ) );
		node.setNote( rule.getNote( ) );
		node.setGroup( rule.getGroup( ) );
		node.setFront( rule.getFront( ) );
		node.setOptional( rule.getOptional( ) );
		return node;
	}

	@Override
	public void afterPropertiesSet( ) throws Exception
	{
		if ( this.ruleTreeEngine == null )
		{
			ruleTreeEngine = new DefaultRuleTreeEngine( );
		}
		Assert.state( ruleTreeEngine != null, "规则引擎不能为空." );
		Assert.notNull( ruleTreeEngine.getRootNode( ) );
	}
	
}
